﻿/*
	Copyright (c) 2005 by Sean Kent. All rights reserved.
	Permission to use, copy, modify and distribute this software for any
	purpose is hereby granted without fee, provided this copyright and
	permissions notice appear in all copies and derivatives.
*/
#region Using directives

using System;
using System.Reflection;
using System.IO;

#endregion

namespace Slobby.Common.NetworkFormatter {
	public class ObjectWriter {
		public ObjectWriter(AssemblyTypeInformation typeInformationStore) {
			this.typeInformationStore = typeInformationStore;
		}

		public void Serialize(BinaryWriter serializationStream, object graph) {
			Type graphType = graph.GetType();
			
			typeInformationStore.AssertIsAssemblyType(graphType);
			WriteObject(serializationStream, graphType, graph);
		}

		private void WriteObject(BinaryWriter serializationStream, Type graphType, object graph) {
			MethodInfo serializationMethod = typeof(BinaryWriter).GetMethod("Write", new Type[] { graphType });
			if (serializationMethod != null) {
				WritePrimitive(serializationStream, graph, serializationMethod);
			} else {
				WriteSerializableObject(serializationStream, graphType, graph);
			}
		}

		private void WriteSerializableObject(BinaryWriter serializationStream, Type graphType, object graph) {
			int id = typeInformationStore.GetIdFromType(graphType);

			serializationStream.Write(id);
			WriteFields(serializationStream, graphType, graph);
		}

		private void WriteFields(BinaryWriter serializationStream, Type graphType, object graph) {
			foreach (FieldInfo field in typeInformationStore.GetFieldsFromType(graphType)) {
				WriteObject(serializationStream, field.FieldType, field.GetValue(graph));
			}
		}

		private static void WritePrimitive(BinaryWriter serializationStream, object graph, MethodInfo serializationMethod) {
			serializationMethod.Invoke(serializationStream, new object[] { graph });
		}

		private AssemblyTypeInformation typeInformationStore;
	}
}
